import 'dart:math';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;

class CommonPieGestureRecognizer extends PanGestureRecognizer {
  CommonPieGestureRecognizer();
}

class CommonPieWidget extends StatefulWidget {
  final List<Map<String, double>> listData;
  final List<Color> colors;

  const CommonPieWidget(this.listData, this.colors, {Key? key})
      : super(key: key);

  @override
  State<StatefulWidget> createState() => _CommonPieWidgetState();
}

class _CommonPieWidgetState extends State<CommonPieWidget> {
  late Offset _startOffset, _updateOffset, _centerOffset;
  final GlobalKey _key = GlobalKey();
  var rotateAngle = 0.0;

  @override
  Widget build(BuildContext context) {
    return SizedBox(
        width: double.infinity,
        height: double.infinity,
        child: RawGestureDetector(
            child: CustomPaint(
                key: _key,
                painter: CommonPiePainter(
                    widget.listData, rotateAngle, widget.colors)),
            gestures: <Type, GestureRecognizerFactory>{
              CommonPieGestureRecognizer: GestureRecognizerFactoryWithHandlers<
                      CommonPieGestureRecognizer>(
                  () => CommonPieGestureRecognizer(),
                  (CommonPieGestureRecognizer gesture) {
                gesture.onDown = (detail) {
                  RenderBox? box =
                      _key.currentContext!.findRenderObject() as RenderBox?;
                  Offset offset = box!.localToGlobal(Offset.zero);
                  _centerOffset = Offset(offset.dx + box.size.width * 0.5,
                      offset.dy + box.size.height * 0.5);
                  _startOffset = detail.globalPosition;
                };
                gesture.onUpdate = (detail) {
                  _updateOffset = detail.globalPosition;
                  setState(() {
                    rotateAngle += _rotateAngle();
                  });
                  _startOffset = _updateOffset;
                };
                gesture.onEnd = (detail) {
                  debugPrint(
                      '---onEnd---$detail---${detail.primaryVelocity}---${detail.velocity}---${detail.velocity.pixelsPerSecond}');
                };
              })
            }));
  }

  _rotateAngle() {
    var gestureDirection = 1;
    if (_startOffset.dy < _centerOffset.dy) {
      gestureDirection = -1;
    } else {
      gestureDirection = 1;
    }
    var _updateAngle = gestureDirection *
        _angle(_updateOffset, Offset(_centerOffset.dx + 100, _centerOffset.dy),
            _centerOffset);
    if (_updateOffset.dy < _centerOffset.dy) {
      gestureDirection = -1;
    } else {
      gestureDirection = 1;
    }
    var _startAngle = gestureDirection *
        _angle(_startOffset, Offset(_centerOffset.dx + 100, _centerOffset.dy),
            _centerOffset);
    return (_updateAngle - _startAngle);
  }

  _angle(_aPoint, _bPoint, _oPoint) {
    var _oALen =
        sqrt(pow(_aPoint.dx - _oPoint.dx, 2) + pow(_aPoint.dy - _oPoint.dy, 2));
    var _oBLen =
        sqrt(pow(_bPoint.dx - _oPoint.dx, 2) + pow(_bPoint.dy - _oPoint.dy, 2));
    var _aBLen =
        sqrt(pow(_aPoint.dx - _bPoint.dx, 2) + pow(_aPoint.dy - _bPoint.dy, 2));
    var _cosAngle = (pow(_oALen, 2) + pow(_oBLen, 2) - pow(_aBLen, 2)) /
        (2 * _oALen * _oBLen);
    return acos(_cosAngle);
  }
}

const PI = 3.1415926;
const _pieRadius = 110.0;

class CommonPiePainter extends CustomPainter {
  List<Map<String, double>> _listData = [];
  List<Color> colors = [];
  var _rotateAngle = 0.0;
  double _sum = 0.0;
  String _subName = '';

  CommonPiePainter(this._listData, this._rotateAngle, this.colors);

  @override
  void paint(Canvas canvas, Size size) {
    double startAngle = 0.0, sweepAngle = 0.0;
    Rect _circle = Rect.fromCircle(
        center: Offset(size.width * 0.5, size.height * 0.5),
        radius: _pieRadius);
    Paint _paint = Paint()
      ..color = Colors.grey
      ..strokeWidth = 4.0
      ..style = PaintingStyle.fill;
    ui.ParagraphBuilder _pb = ui.ParagraphBuilder(ui.ParagraphStyle(
        textAlign: TextAlign.left,
        fontWeight: FontWeight.w600,
        fontStyle: FontStyle.normal,
        fontSize: 14))
      ..pushStyle(ui.TextStyle(color: Colors.white));
    ui.ParagraphConstraints _paragraph =
        ui.ParagraphConstraints(width: size.width * 0.5);
    _sumData();
    if (_rotateAngle == null) {
      _rotateAngle = 0.0;
    }
    if (_listData.isNotEmpty) {
      for (int i = 0; i < _listData.length; i++) {
        startAngle += sweepAngle;
        sweepAngle = _listData[i].values.first * 2 * PI / _sum;
        canvas.drawArc(_circle, startAngle + _rotateAngle, sweepAngle, true,
            _paint..color = _subPaint(_listData[i].keys.first, i));

        if (sweepAngle >= PI / 6) {
          canvas.translate(size.width * 0.5, size.height * 0.5);
          canvas.rotate(startAngle + sweepAngle * 0.5 + _rotateAngle);
          ui.Paragraph paragraph = (_pb..addText(_subName)).build()
            ..layout(_paragraph);
          canvas.drawParagraph(
              paragraph, Offset(50.0, 0.0 - paragraph.height * 0.5));
          canvas.rotate(-startAngle - sweepAngle * 0.5 - _rotateAngle);
          canvas.translate(-size.width * 0.5, -size.height * 0.5);
        }
      }
    }
    _sum = 0.0;
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;

  _sumData() {
    if (_listData.isNotEmpty) {
      for (int i = 0; i < _listData.length; i++) {
        debugPrint(
            '----${_listData[i].values}---${_listData[i].values.first}---${_listData[i].keys}---${_listData[i].keys.first}');
        _sum += _listData[i].values.first;
        debugPrint('---$_sum---');
      }
    }
  }

  _subPaint(type, index) {
    Color _color;
    _color = colors[index];
    _subName = type;
    return _color;
  }
}
